use core::{ffi::c_void, ptr::null_mut};

use libc::{atexit, CLOCK_MONOTONIC};

use crate::{
    heap::{_mi_heap_random, default_heap, mi_get_default_heap, mi_set_default_heap},
    internal::{_mi_thread_id, mi_heap_is_initialized},
    os::_mi_os_alloc,
    stats::{mi_stat_increase, mi_stats_reset},
    types::*,
};

pub static mut _mi_page_empty: mi_page_t = unsafe { core::mem::zeroed() };

pub static mut _mi_heap_empty: mi_heap_t = unsafe {
    mi_heap_t {
        tld: null_mut(),
        pages_free_direct: [&mut _mi_page_empty; 130],
        pages: [
            mi_page_queue_t {
                first: null_mut(),
                last: null_mut(),
                block_size: size_of::<*const ()>() * 1,
            },
            mi_page_queue_t {
                first: null_mut(),
                last: null_mut(),
                block_size: size_of::<*const ()>() * 1,
            },
            mi_page_queue_t {
                first: null_mut(),
                last: null_mut(),
                block_size: size_of::<*const ()>() * 2,
            },
            mi_page_queue_t {
                first: null_mut(),
                last: null_mut(),
                block_size: size_of::<*const ()>() * 3,
            },
            mi_page_queue_t {
                first: null_mut(),
                last: null_mut(),
                block_size: size_of::<*const ()>() * 4,
            },
            mi_page_queue_t {
                first: null_mut(),
                last: null_mut(),
                block_size: size_of::<*const ()>() * 5,
            },
            mi_page_queue_t {
                first: null_mut(),
                last: null_mut(),
                block_size: size_of::<*const ()>() * 6,
            },
            mi_page_queue_t {
                first: null_mut(),
                last: null_mut(),
                block_size: size_of::<*const ()>() * 7,
            },
            mi_page_queue_t {
                first: null_mut(),
                last: null_mut(),
                block_size: size_of::<*const ()>() * 8,
            },
            mi_page_queue_t {
                first: null_mut(),
                last: null_mut(),
                block_size: size_of::<*const ()>() * 10,
            },
            mi_page_queue_t {
                first: null_mut(),
                last: null_mut(),
                block_size: size_of::<*const ()>() * 12,
            },
            mi_page_queue_t {
                first: null_mut(),
                last: null_mut(),
                block_size: size_of::<*const ()>() * 14,
            },
            mi_page_queue_t {
                first: null_mut(),
                last: null_mut(),
                block_size: size_of::<*const ()>() * 16,
            },
            mi_page_queue_t {
                first: null_mut(),
                last: null_mut(),
                block_size: size_of::<*const ()>() * 20,
            },
            mi_page_queue_t {
                first: null_mut(),
                last: null_mut(),
                block_size: size_of::<*const ()>() * 24,
            },
            mi_page_queue_t {
                first: null_mut(),
                last: null_mut(),
                block_size: size_of::<*const ()>() * 28,
            },
            mi_page_queue_t {
                first: null_mut(),
                last: null_mut(),
                block_size: size_of::<*const ()>() * 32,
            },
            mi_page_queue_t {
                first: null_mut(),
                last: null_mut(),
                block_size: size_of::<*const ()>() * 40,
            },
            mi_page_queue_t {
                first: null_mut(),
                last: null_mut(),
                block_size: size_of::<*const ()>() * 48,
            },
            mi_page_queue_t {
                first: null_mut(),
                last: null_mut(),
                block_size: size_of::<*const ()>() * 56,
            },
            mi_page_queue_t {
                first: null_mut(),
                last: null_mut(),
                block_size: size_of::<*const ()>() * 64,
            },
            mi_page_queue_t {
                first: null_mut(),
                last: null_mut(),
                block_size: size_of::<*const ()>() * 80,
            },
            mi_page_queue_t {
                first: null_mut(),
                last: null_mut(),
                block_size: size_of::<*const ()>() * 96,
            },
            mi_page_queue_t {
                first: null_mut(),
                last: null_mut(),
                block_size: size_of::<*const ()>() * 112,
            },
            mi_page_queue_t {
                first: null_mut(),
                last: null_mut(),
                block_size: size_of::<*const ()>() * 128,
            },
            mi_page_queue_t {
                first: null_mut(),
                last: null_mut(),
                block_size: size_of::<*const ()>() * 160,
            },
            mi_page_queue_t {
                first: null_mut(),
                last: null_mut(),
                block_size: size_of::<*const ()>() * 192,
            },
            mi_page_queue_t {
                first: null_mut(),
                last: null_mut(),
                block_size: size_of::<*const ()>() * 224,
            },
            mi_page_queue_t {
                first: null_mut(),
                last: null_mut(),
                block_size: size_of::<*const ()>() * 256,
            },
            mi_page_queue_t {
                first: null_mut(),
                last: null_mut(),
                block_size: size_of::<*const ()>() * 320,
            },
            mi_page_queue_t {
                first: null_mut(),
                last: null_mut(),
                block_size: size_of::<*const ()>() * 384,
            },
            mi_page_queue_t {
                first: null_mut(),
                last: null_mut(),
                block_size: size_of::<*const ()>() * 448,
            },
            mi_page_queue_t {
                first: null_mut(),
                last: null_mut(),
                block_size: size_of::<*const ()>() * 512,
            },
            mi_page_queue_t {
                first: null_mut(),
                last: null_mut(),
                block_size: size_of::<*const ()>() * 640,
            },
            mi_page_queue_t {
                first: null_mut(),
                last: null_mut(),
                block_size: size_of::<*const ()>() * 768,
            },
            mi_page_queue_t {
                first: null_mut(),
                last: null_mut(),
                block_size: size_of::<*const ()>() * 896,
            },
            mi_page_queue_t {
                first: null_mut(),
                last: null_mut(),
                block_size: size_of::<*const ()>() * 1024,
            },
            mi_page_queue_t {
                first: null_mut(),
                last: null_mut(),
                block_size: size_of::<*const ()>() * 1280,
            },
            mi_page_queue_t {
                first: null_mut(),
                last: null_mut(),
                block_size: size_of::<*const ()>() * 1536,
            },
            mi_page_queue_t {
                first: null_mut(),
                last: null_mut(),
                block_size: size_of::<*const ()>() * 1792,
            },
            mi_page_queue_t {
                first: null_mut(),
                last: null_mut(),
                block_size: size_of::<*const ()>() * 2048,
            },
            mi_page_queue_t {
                first: null_mut(),
                last: null_mut(),
                block_size: size_of::<*const ()>() * 2560,
            },
            mi_page_queue_t {
                first: null_mut(),
                last: null_mut(),
                block_size: size_of::<*const ()>() * 3072,
            },
            mi_page_queue_t {
                first: null_mut(),
                last: null_mut(),
                block_size: size_of::<*const ()>() * 3584,
            },
            mi_page_queue_t {
                first: null_mut(),
                last: null_mut(),
                block_size: size_of::<*const ()>() * 4096,
            },
            mi_page_queue_t {
                first: null_mut(),
                last: null_mut(),
                block_size: size_of::<*const ()>() * 5120,
            },
            mi_page_queue_t {
                first: null_mut(),
                last: null_mut(),
                block_size: size_of::<*const ()>() * 6144,
            },
            mi_page_queue_t {
                first: null_mut(),
                last: null_mut(),
                block_size: size_of::<*const ()>() * 7168,
            },
            mi_page_queue_t {
                first: null_mut(),
                last: null_mut(),
                block_size: size_of::<*const ()>() * 8192,
            },
            mi_page_queue_t {
                first: null_mut(),
                last: null_mut(),
                block_size: size_of::<*const ()>() * 10240,
            },
            mi_page_queue_t {
                first: null_mut(),
                last: null_mut(),
                block_size: size_of::<*const ()>() * 12288,
            },
            mi_page_queue_t {
                first: null_mut(),
                last: null_mut(),
                block_size: size_of::<*const ()>() * 14336,
            },
            mi_page_queue_t {
                first: null_mut(),
                last: null_mut(),
                block_size: size_of::<*const ()>() * 16384,
            },
            mi_page_queue_t {
                first: null_mut(),
                last: null_mut(),
                block_size: size_of::<*const ()>() * 20480,
            },
            mi_page_queue_t {
                first: null_mut(),
                last: null_mut(),
                block_size: size_of::<*const ()>() * 24576,
            },
            mi_page_queue_t {
                first: null_mut(),
                last: null_mut(),
                block_size: size_of::<*const ()>() * 28672,
            },
            mi_page_queue_t {
                first: null_mut(),
                last: null_mut(),
                block_size: size_of::<*const ()>() * 32768,
            },
            mi_page_queue_t {
                first: null_mut(),
                last: null_mut(),
                block_size: size_of::<*const ()>() * 40960,
            },
            mi_page_queue_t {
                first: null_mut(),
                last: null_mut(),
                block_size: size_of::<*const ()>() * 49152,
            },
            mi_page_queue_t {
                first: null_mut(),
                last: null_mut(),
                block_size: size_of::<*const ()>() * 57344,
            },
            mi_page_queue_t {
                first: null_mut(),
                last: null_mut(),
                block_size: size_of::<*const ()>() * 65536,
            },
            mi_page_queue_t {
                first: null_mut(),
                last: null_mut(),
                block_size: size_of::<*const ()>() * 81920,
            },
            mi_page_queue_t {
                first: null_mut(),
                last: null_mut(),
                block_size: size_of::<*const ()>() * 98304,
            },
            mi_page_queue_t {
                first: null_mut(),
                last: null_mut(),
                block_size: size_of::<*const ()>() * 114688,
            },
            mi_page_queue_t {
                first: null_mut(),
                last: null_mut(),
                block_size: size_of::<*const ()>() * (MI_LARGE_WSIZE_MAX as usize + 1),
            },
            mi_page_queue_t {
                first: null_mut(),
                last: null_mut(),
                block_size: size_of::<*const ()>() * (MI_LARGE_WSIZE_MAX as usize + 2),
            },
        ],
        thread_delayed_free: null_mut(),
        thread_id: 0,
        cookie: 0,
        random: 0,
        page_count: 0,
        no_reclaim: false,
    }
};

pub static mut tld_main: mi_tld_t = {
    unsafe {
        mi_tld_t {
            heartbeat: 0,
            heap_backing: &mut _mi_heap_main as _,
            segments: mi_segments_tld_t {
                small_free: mi_segment_queue_t {
                    first: null_mut(),
                    last: null_mut(),
                },
                current_size: 0,
                peak_size: 0,
                cache_count: 0,
                cache_size: 0,
                cache: mi_segment_queue_t {
                    first: null_mut(),
                    last: null_mut(),
                },
                stats: &mut tld_main.stats as _,
            },
            os: mi_os_tld_t {
                mmap_next_probable: 0,
                mmap_previous: null_mut(),
                pool: null_mut(),
                pool_available: 0,
                stats: &mut tld_main.stats as _,
            },
            stats: core::mem::zeroed(),
        }
    }
};

pub static mut _mi_heap_main: mi_heap_t = unsafe {
    mi_heap_t {
        tld: &mut tld_main,
        pages_free_direct: [&mut _mi_page_empty; 130],
        pages: [
            mi_page_queue_t {
                first: null_mut(),
                last: null_mut(),
                block_size: size_of::<*const ()>() * 1,
            },
            mi_page_queue_t {
                first: null_mut(),
                last: null_mut(),
                block_size: size_of::<*const ()>() * 1,
            },
            mi_page_queue_t {
                first: null_mut(),
                last: null_mut(),
                block_size: size_of::<*const ()>() * 2,
            },
            mi_page_queue_t {
                first: null_mut(),
                last: null_mut(),
                block_size: size_of::<*const ()>() * 3,
            },
            mi_page_queue_t {
                first: null_mut(),
                last: null_mut(),
                block_size: size_of::<*const ()>() * 4,
            },
            mi_page_queue_t {
                first: null_mut(),
                last: null_mut(),
                block_size: size_of::<*const ()>() * 5,
            },
            mi_page_queue_t {
                first: null_mut(),
                last: null_mut(),
                block_size: size_of::<*const ()>() * 6,
            },
            mi_page_queue_t {
                first: null_mut(),
                last: null_mut(),
                block_size: size_of::<*const ()>() * 7,
            },
            mi_page_queue_t {
                first: null_mut(),
                last: null_mut(),
                block_size: size_of::<*const ()>() * 8,
            },
            mi_page_queue_t {
                first: null_mut(),
                last: null_mut(),
                block_size: size_of::<*const ()>() * 10,
            },
            mi_page_queue_t {
                first: null_mut(),
                last: null_mut(),
                block_size: size_of::<*const ()>() * 12,
            },
            mi_page_queue_t {
                first: null_mut(),
                last: null_mut(),
                block_size: size_of::<*const ()>() * 14,
            },
            mi_page_queue_t {
                first: null_mut(),
                last: null_mut(),
                block_size: size_of::<*const ()>() * 16,
            },
            mi_page_queue_t {
                first: null_mut(),
                last: null_mut(),
                block_size: size_of::<*const ()>() * 20,
            },
            mi_page_queue_t {
                first: null_mut(),
                last: null_mut(),
                block_size: size_of::<*const ()>() * 24,
            },
            mi_page_queue_t {
                first: null_mut(),
                last: null_mut(),
                block_size: size_of::<*const ()>() * 28,
            },
            mi_page_queue_t {
                first: null_mut(),
                last: null_mut(),
                block_size: size_of::<*const ()>() * 32,
            },
            mi_page_queue_t {
                first: null_mut(),
                last: null_mut(),
                block_size: size_of::<*const ()>() * 40,
            },
            mi_page_queue_t {
                first: null_mut(),
                last: null_mut(),
                block_size: size_of::<*const ()>() * 48,
            },
            mi_page_queue_t {
                first: null_mut(),
                last: null_mut(),
                block_size: size_of::<*const ()>() * 56,
            },
            mi_page_queue_t {
                first: null_mut(),
                last: null_mut(),
                block_size: size_of::<*const ()>() * 64,
            },
            mi_page_queue_t {
                first: null_mut(),
                last: null_mut(),
                block_size: size_of::<*const ()>() * 80,
            },
            mi_page_queue_t {
                first: null_mut(),
                last: null_mut(),
                block_size: size_of::<*const ()>() * 96,
            },
            mi_page_queue_t {
                first: null_mut(),
                last: null_mut(),
                block_size: size_of::<*const ()>() * 112,
            },
            mi_page_queue_t {
                first: null_mut(),
                last: null_mut(),
                block_size: size_of::<*const ()>() * 128,
            },
            mi_page_queue_t {
                first: null_mut(),
                last: null_mut(),
                block_size: size_of::<*const ()>() * 160,
            },
            mi_page_queue_t {
                first: null_mut(),
                last: null_mut(),
                block_size: size_of::<*const ()>() * 192,
            },
            mi_page_queue_t {
                first: null_mut(),
                last: null_mut(),
                block_size: size_of::<*const ()>() * 224,
            },
            mi_page_queue_t {
                first: null_mut(),
                last: null_mut(),
                block_size: size_of::<*const ()>() * 256,
            },
            mi_page_queue_t {
                first: null_mut(),
                last: null_mut(),
                block_size: size_of::<*const ()>() * 320,
            },
            mi_page_queue_t {
                first: null_mut(),
                last: null_mut(),
                block_size: size_of::<*const ()>() * 384,
            },
            mi_page_queue_t {
                first: null_mut(),
                last: null_mut(),
                block_size: size_of::<*const ()>() * 448,
            },
            mi_page_queue_t {
                first: null_mut(),
                last: null_mut(),
                block_size: size_of::<*const ()>() * 512,
            },
            mi_page_queue_t {
                first: null_mut(),
                last: null_mut(),
                block_size: size_of::<*const ()>() * 640,
            },
            mi_page_queue_t {
                first: null_mut(),
                last: null_mut(),
                block_size: size_of::<*const ()>() * 768,
            },
            mi_page_queue_t {
                first: null_mut(),
                last: null_mut(),
                block_size: size_of::<*const ()>() * 896,
            },
            mi_page_queue_t {
                first: null_mut(),
                last: null_mut(),
                block_size: size_of::<*const ()>() * 1024,
            },
            mi_page_queue_t {
                first: null_mut(),
                last: null_mut(),
                block_size: size_of::<*const ()>() * 1280,
            },
            mi_page_queue_t {
                first: null_mut(),
                last: null_mut(),
                block_size: size_of::<*const ()>() * 1536,
            },
            mi_page_queue_t {
                first: null_mut(),
                last: null_mut(),
                block_size: size_of::<*const ()>() * 1792,
            },
            mi_page_queue_t {
                first: null_mut(),
                last: null_mut(),
                block_size: size_of::<*const ()>() * 2048,
            },
            mi_page_queue_t {
                first: null_mut(),
                last: null_mut(),
                block_size: size_of::<*const ()>() * 2560,
            },
            mi_page_queue_t {
                first: null_mut(),
                last: null_mut(),
                block_size: size_of::<*const ()>() * 3072,
            },
            mi_page_queue_t {
                first: null_mut(),
                last: null_mut(),
                block_size: size_of::<*const ()>() * 3584,
            },
            mi_page_queue_t {
                first: null_mut(),
                last: null_mut(),
                block_size: size_of::<*const ()>() * 4096,
            },
            mi_page_queue_t {
                first: null_mut(),
                last: null_mut(),
                block_size: size_of::<*const ()>() * 5120,
            },
            mi_page_queue_t {
                first: null_mut(),
                last: null_mut(),
                block_size: size_of::<*const ()>() * 6144,
            },
            mi_page_queue_t {
                first: null_mut(),
                last: null_mut(),
                block_size: size_of::<*const ()>() * 7168,
            },
            mi_page_queue_t {
                first: null_mut(),
                last: null_mut(),
                block_size: size_of::<*const ()>() * 8192,
            },
            mi_page_queue_t {
                first: null_mut(),
                last: null_mut(),
                block_size: size_of::<*const ()>() * 10240,
            },
            mi_page_queue_t {
                first: null_mut(),
                last: null_mut(),
                block_size: size_of::<*const ()>() * 12288,
            },
            mi_page_queue_t {
                first: null_mut(),
                last: null_mut(),
                block_size: size_of::<*const ()>() * 14336,
            },
            mi_page_queue_t {
                first: null_mut(),
                last: null_mut(),
                block_size: size_of::<*const ()>() * 16384,
            },
            mi_page_queue_t {
                first: null_mut(),
                last: null_mut(),
                block_size: size_of::<*const ()>() * 20480,
            },
            mi_page_queue_t {
                first: null_mut(),
                last: null_mut(),
                block_size: size_of::<*const ()>() * 24576,
            },
            mi_page_queue_t {
                first: null_mut(),
                last: null_mut(),
                block_size: size_of::<*const ()>() * 28672,
            },
            mi_page_queue_t {
                first: null_mut(),
                last: null_mut(),
                block_size: size_of::<*const ()>() * 32768,
            },
            mi_page_queue_t {
                first: null_mut(),
                last: null_mut(),
                block_size: size_of::<*const ()>() * 40960,
            },
            mi_page_queue_t {
                first: null_mut(),
                last: null_mut(),
                block_size: size_of::<*const ()>() * 49152,
            },
            mi_page_queue_t {
                first: null_mut(),
                last: null_mut(),
                block_size: size_of::<*const ()>() * 57344,
            },
            mi_page_queue_t {
                first: null_mut(),
                last: null_mut(),
                block_size: size_of::<*const ()>() * 65536,
            },
            mi_page_queue_t {
                first: null_mut(),
                last: null_mut(),
                block_size: size_of::<*const ()>() * 81920,
            },
            mi_page_queue_t {
                first: null_mut(),
                last: null_mut(),
                block_size: size_of::<*const ()>() * 98304,
            },
            mi_page_queue_t {
                first: null_mut(),
                last: null_mut(),
                block_size: size_of::<*const ()>() * 114688,
            },
            mi_page_queue_t {
                first: null_mut(),
                last: null_mut(),
                block_size: size_of::<*const ()>() * (MI_LARGE_WSIZE_MAX as usize + 1),
            },
            mi_page_queue_t {
                first: null_mut(),
                last: null_mut(),
                block_size: size_of::<*const ()>() * (MI_LARGE_WSIZE_MAX as usize + 2),
            },
        ],
        thread_delayed_free: null_mut(),
        thread_id: 0,
        cookie: 0,
        random: 0,
        page_count: 0,
        no_reclaim: false,
    }
};

// pub static mut _mi_heap_default: static_mi_heap_t_ptr =
//     unsafe { static_mi_heap_t_ptr(&mut _mi_heap_empty as _) };

pub static mut _mi_stats_main: mi_stats_t = unsafe { core::mem::zeroed() };

pub static mut _mi_process_is_initialized: bool = false;

// This is called from the `mi_malloc_generic`
pub unsafe fn mi_thread_init() {
    // ensure our process has started already
    mi_process_init();
    
    // initialize the thread local default heap
    if _mi_heap_init() {
        return;
    }

    if _mi_is_main_thread() {
        return;
    }

    let heap = mi_get_default_heap();
    libc::printf("heap: %p\n\0".as_ptr() as _, heap);
    mi_stat_increase(&mut (&mut *(&mut *heap).tld).stats.threads, 1);
    // TODO! pthread
}

pub unsafe fn mi_process_init() {
    if _mi_process_is_initialized {
        return;
    }
    libc::pthread_key_create(&mut default_heap, None);
    _mi_process_is_initialized = true;
    _mi_heap_main.thread_id = _mi_thread_id();
    let random = _mi_random_init(_mi_heap_main.thread_id);
    _mi_heap_main.cookie = &_mi_heap_main as *const _ as usize ^ random;
    _mi_heap_main.random = _mi_random_shuffle(random);
    atexit(mi_process_done);
    mi_process_setup_auto_thread_done();
    mi_stats_reset();
}

pub extern "C" fn mi_process_done() {
    unsafe {
        if !_mi_process_is_initialized {
            return;
        }
        static mut process_done: bool = false;
        if process_done {
            return;
        }
        process_done = true;
        // TODO! option
    }
}

pub unsafe fn _mi_random_init(seed: usize) -> usize {
    let mut x = &_mi_random_init as *const _ as usize;
    x ^= seed;
    let mut time = core::mem::zeroed();
    libc::clock_gettime(CLOCK_MONOTONIC, &mut time);
    x ^= time.tv_sec as usize;
    x ^= time.tv_nsec as usize;
    let max = ((x ^ (x >> 17)) & 0x0F) + 1;
    for _ in 0..max {
        x = _mi_random_shuffle(x)
    }
    x
}

pub unsafe fn _mi_random_shuffle(mut x: usize) -> usize {
    if MI_INTPTR_SIZE == 8 {
        x ^= x >> 30;
        x = x.wrapping_mul(0xbf58476d1ce4e5b9);
        x ^= x >> 27;
        x = x.wrapping_mul(0x94d049bb133111eb);
        x ^= x >> 31;
    } else if MI_INTPTR_SIZE == 4 {
        x ^= x >> 16;
        x = x.wrapping_mul(0x7feb352d);
        x ^= x >> 15;
        x = x.wrapping_mul(0x846ca68b);
        x ^= x >> 16;
    }
    x
}

pub unsafe fn mi_process_setup_auto_thread_done() {
    static mut tls_initialized: bool = false;
    if tls_initialized {
        return;
    }
    tls_initialized = true;
    // TODO! pthread_key_create(&mi_pthread_key, &mi_pthread_done);
}

pub unsafe fn _mi_is_main_thread() -> bool {
    _mi_heap_main.thread_id == 0 || _mi_heap_main.thread_id == _mi_thread_id()
}

pub struct mi_thread_data_t {
    heap: mi_heap_t,
    tld: mi_tld_t,
}

pub unsafe fn _mi_heap_init() -> bool {
    if mi_heap_is_initialized(mi_get_default_heap()) {
        return true;
    }

    if _mi_is_main_thread() {
        mi_set_default_heap(&mut _mi_heap_main);
        //debug_assert!((&mut *_mi_heap_main.tld).heap_backing == _mi_heap_default.0)
    } else {
        let td = _mi_os_alloc(size_of::<mi_thread_data_t>(), &mut _mi_stats_main)
            as *mut mi_thread_data_t;
        if td.is_null() {
            return false;
        }

        let tld = &mut (&mut *td).tld;
        let heap = &mut (&mut *td).heap;
        *heap = core::mem::transmute_copy(&_mi_heap_empty);
        heap.thread_id = _mi_thread_id();
        heap.random = _mi_random_init(heap.thread_id);
        heap.cookie = ((heap as *const _ as usize) ^ _mi_heap_random(heap)) | 1;
        heap.tld = tld;
        *tld = core::mem::zeroed();
        tld.heap_backing = heap;
        tld.segments.stats = &mut tld.stats;
        tld.os.stats = &mut tld.stats;
        mi_set_default_heap(heap);
    }

    return false;
}

pub unsafe fn _mi_ptr_cookie(p: *mut c_void) -> usize {
    p as usize ^ _mi_heap_main.cookie
}
